/* Hey Emacs, this is -*- mode: java; page-delimiter: "^%%$"; -*- */

/*
 * Copyright © 2002 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * California 95054, U.S.A. All rights reserved.  Sun Microsystems, Inc. has
 * intellectual property rights relating to technology embodied in the product
 * that is described in this document. In particular, and without limitation,
 * these intellectual property rights may include one or more of the U.S.
 * patents listed at http://www.sun.com/patents and one or more additional
 * patents or pending patent applications in the U.S. and in other countries.
 * U.S. Government Rights - Commercial software. Government users are subject
 * to the Sun Microsystems, Inc. standard license agreement and applicable
 * provisions of the FAR and its supplements.  Use is subject to license terms.
 * Sun,  Sun Microsystems,  the Sun logo and  Java are trademarks or registered
 * trademarks of Sun Microsystems, Inc. in the U.S. and other countries.  This
 * product is covered and controlled by U.S. Export Control laws and may be
 * subject to the export or import laws in other countries.  Nuclear, missile,
 * chemical biological weapons or nuclear maritime end uses or end users,
 * whether direct or indirect, are strictly prohibited.  Export or reexport
 * to countries subject to U.S. embargo or to entities identified on U.S.
 * export exclusion lists, including, but not limited to, the denied persons
 * and specially designated nationals lists is strictly prohibited.
 */

options {
  JAVA_UNICODE_ESCAPE = true;
  ERROR_REPORTING = false;
  STATIC = false;
  USER_CHAR_STREAM = true;
}

PARSER_BEGIN(JavaParser)
package jplag.java15.grammar;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import jplag.UnicodeReader;
import jplag.java15.JavaTokenConstants;

/**
 * Grammar to parse Java version 1.5
 * @author Sreenivasa Viswanadha - Simplified and enhanced for 1.5
 */
public class JavaParser implements JavaTokenConstants
{
    /**
     * Class to hold modifiers.
     */
  
    private jplag.java15.Parser parser2;
    static public final class ModifierSet
    {
        /* Definitions of the bits in the modifiers field.  */
        public static final int PUBLIC = 0x0001;
        public static final int PROTECTED = 0x0002;
        public static final int PRIVATE = 0x0004;
        public static final int ABSTRACT = 0x0008;
        public static final int STATIC = 0x0010;
        public static final int FINAL = 0x0020;
        public static final int SYNCHRONIZED = 0x0040;
        public static final int NATIVE = 0x0080;
        public static final int TRANSIENT = 0x0100;
        public static final int VOLATILE = 0x0200;
        public static final int STRICTFP = 0x1000;

        /** A set of accessors that indicate whether the specified modifier is in the set. */

        public boolean isPublic(int modifiers)
        {
            return (modifiers & PUBLIC) != 0;
        }

        public boolean isProtected(int modifiers)
        {
            return (modifiers & PROTECTED) != 0;
        }

        public boolean isPrivate(int modifiers)
        {
            return (modifiers & PRIVATE) != 0;
        }

        public boolean isStatic(int modifiers)
        {
            return (modifiers & STATIC) != 0;
        }

        public boolean isAbstract(int modifiers)
        {
            return (modifiers & ABSTRACT) != 0;
        }

        public boolean isFinal(int modifiers)
        {
            return (modifiers & FINAL) != 0;
        }

        public boolean isNative(int modifiers)
        {
            return (modifiers & NATIVE) != 0;
        }

        public boolean isStrictfp(int modifiers)
        {
            return (modifiers & STRICTFP) != 0;
        }

        public boolean isSynchronized(int modifiers)
        {
            return (modifiers & SYNCHRONIZED) != 0;
        }

        public boolean isTransient(int modifiers)
        {
            return (modifiers & TRANSIENT) != 0;
        }

        public boolean isVolatile(int modifiers)
        {
            return (modifiers & VOLATILE) != 0;
        }

        /**
          * Removes the given modifier.
          */
        static int removeModifier(int modifiers, int mod) {
            return modifiers & ~mod;
        }
    }

    //JavaParser parser = null;
    JavaTabModCharStream charStream = null;

    public static boolean parseFile(File dir, String fileName, JavaParser parser, jplag.java15.Parser parserX)
    {
        try {
            FileInputStream in = new FileInputStream(new File(dir,fileName));
            if (parser == null) {
                JavaTabModCharStream charStream = new JavaTabModCharStream(new UnicodeReader(in, "UTF-8"));
                parser = new JavaParser(charStream);
                parser.charStream = charStream;
            } else {
                parser.charStream.ReInit(new UnicodeReader(in, "UTF-8"));
                parser.ReInit(parser.charStream);
            }
            parser.parser2 = parserX;
        } catch (FileNotFoundException e) {
            System.out.println("Java Parser: File " + fileName + " not found.");
            return false;
        }
        try {
            parser.CompilationUnit();
        } catch (ParseException e) {
            parserX.getProgram().addError("  Parsing Error in '" + fileName + "':\n  " + e.getMessage() + "\n");
            return false;
        } catch (TokenMgrError e) {
            parserX.getProgram().addError("  Scanning Error in '" + fileName + "':\n  " + e.getMessage() + "\n");
            return false;
        } catch (Exception e) {
            parserX.getProgram().addError("  General error in '" + fileName + "':\n  " + e.getMessage() + "\n");
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

PARSER_END(JavaParser)

/* WHITE SPACE */

SKIP :
{
  " "
| "\t"
| "\n"
| "\r"
| "\f"
}

/* COMMENTS */

SPECIAL_TOKEN :
{
  <SINGLE_LINE_COMMENT: "//" (~["\n", "\r"])* ("\n" | "\r" | "\r\n")? >
}

MORE :
{
  <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
|
  "/*" : IN_MULTI_LINE_COMMENT
}

<IN_FORMAL_COMMENT>
SPECIAL_TOKEN :
{
  <FORMAL_COMMENT: "*/" > : DEFAULT
}

<IN_MULTI_LINE_COMMENT>
SPECIAL_TOKEN :
{
  <MULTI_LINE_COMMENT: "*/" > : DEFAULT
}

<IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
MORE :
{
  < ~[] >
}

/* RESERVED WORDS AND LITERALS */

TOKEN :
{
  < ABSTRACT: "abstract" >
| < ASSERT: "assert" >
| < BOOLEAN: "boolean" >
| < BREAK: "break" >
| < BYTE: "byte" >
| < CASE: "case" >
| < CATCH: "catch" >
| < CHAR: "char" >
| < CLASS: "class" >
| < CONST: "const" >
| < CONTINUE: "continue" >
| < _DEFAULT: "default" >
| < DO: "do" >
| < DOUBLE: "double" >
| < ELSE: "else" >
| < ENUM: "enum" >
| < EXTENDS: "extends" >
| < FALSE: "false" >
| < FINAL: "final" >
| < FINALLY: "finally" >
| < FLOAT: "float" >
| < FOR: "for" >
| < GOTO: "goto" >
| < IF: "if" >
| < IMPLEMENTS: "implements" >
| < IMPORT: "import" >
| < INSTANCEOF: "instanceof" >
| < INT: "int" >
| < INTERFACE: "interface" >
| < LONG: "long" >
| < NATIVE: "native" >
| < NEW: "new" >
| < NULL: "null" >
| < PACKAGE: "package">
| < PRIVATE: "private" >
| < PROTECTED: "protected" >
| < PUBLIC: "public" >
| < RETURN: "return" >
| < SHORT: "short" >
| < STATIC: "static" >
| < STRICTFP: "strictfp" >
| < SUPER: "super" >
| < SWITCH: "switch" >
| < SYNCHRONIZED: "synchronized" >
| < THIS: "this" >
| < THROW: "throw" >
| < THROWS: "throws" >
| < TRANSIENT: "transient" >
| < TRUE: "true" >
| < TRY: "try" >
| < VOID: "void" >
| < VOLATILE: "volatile" >
| < WHILE: "while" >
}

/* LITERALS */

TOKEN :
{
  < INTEGER_LITERAL:
        <DECIMAL_LITERAL> (["l","L"])?
      | <HEX_LITERAL> (["l","L"])?
      | <OCTAL_LITERAL> (["l","L"])?
  >
|
  < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
|
  < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
|
  < #OCTAL_LITERAL: "0" (["0"-"7"])* >
|
  < FLOATING_POINT_LITERAL:
        (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
      | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
      | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
      | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
  >
|
  < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
|
  < CHARACTER_LITERAL:
      "'"
      (   (~["'","\\","\n","\r"])
        | ("\\"
            ( ["n","t","b","r","f","\\","'","\""]
            | ["0"-"7"] ( ["0"-"7"] )?
            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
            )
          )
      )
      "'"
  >
|
  < STRING_LITERAL:
      "\""
      (   (~["\"","\\","\n","\r"])
        | ("\\"
            ( ["n","t","b","r","f","\\","'","\""]
            | ["0"-"7"] ( ["0"-"7"] )?
            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
            )
          )
      )*
      "\""
  >
}

/* IDENTIFIERS */

TOKEN :
{
  < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
|
  < #LETTER:
      [
       "\u0024",
       "\u0041"-"\u005a",
       "\u005f",
       "\u0061"-"\u007a",
       "\u00c0"-"\u00d6",
       "\u00d8"-"\u00f6",
       "\u00f8"-"\u00ff",
       "\u0100"-"\u1fff",
       "\u3040"-"\u318f",
       "\u3300"-"\u337f",
       "\u3400"-"\u3d2d",
       "\u4e00"-"\u9fff",
       "\uf900"-"\ufaff"
      ]
  >
|
  < #DIGIT:
      [
       "\u0030"-"\u0039",
       "\u0660"-"\u0669",
       "\u06f0"-"\u06f9",
       "\u0966"-"\u096f",
       "\u09e6"-"\u09ef",
       "\u0a66"-"\u0a6f",
       "\u0ae6"-"\u0aef",
       "\u0b66"-"\u0b6f",
       "\u0be7"-"\u0bef",
       "\u0c66"-"\u0c6f",
       "\u0ce6"-"\u0cef",
       "\u0d66"-"\u0d6f",
       "\u0e50"-"\u0e59",
       "\u0ed0"-"\u0ed9",
       "\u1040"-"\u1049"
      ]
  >
}

/* SEPARATORS */

TOKEN :
{
  < LPAREN: "(" >
| < RPAREN: ")" >
| < LBRACE: "{" >
| < RBRACE: "}" >
| < LBRACKET: "[" >
| < RBRACKET: "]" >
| < SEMICOLON: ";" >
| < COMMA: "," >
| < DOT: "." >
| < AT: "@" >
}

/* OPERATORS */

TOKEN :
{
  < ASSIGN: "=" >
| < LT: "<" >
| < BANG: "!" >
| < TILDE: "~" >
| < HOOK: "?" >
| < COLON: ":" >
| < EQ: "==" >
| < LE: "<=" >
| < GE: ">=" >
| < NE: "!=" >
| < SC_OR: "||" >
| < SC_AND: "&&" >
| < INCR: "++" >
| < DECR: "--" >
| < PLUS: "+" >
| < MINUS: "-" >
| < STAR: "*" >
| < SLASH: "/" >
| < BIT_AND: "&" >
| < BIT_OR: "|" >
| < XOR: "^" >
| < REM: "%" >
| < LSHIFT: "<<" >
| < PLUSASSIGN: "+=" >
| < MINUSASSIGN: "-=" >
| < STARASSIGN: "*=" >
| < SLASHASSIGN: "/=" >
| < ANDASSIGN: "&=" >
| < ORASSIGN: "|=" >
| < XORASSIGN: "^=" >
| < REMASSIGN: "%=" >
| < LSHIFTASSIGN: "<<=" >
| < RSIGNEDSHIFTASSIGN: ">>=" >
| < RUNSIGNEDSHIFTASSIGN: ">>>=" >
| < ELLIPSIS: "..." >
}

/* >'s need special attention due to generics syntax. */
TOKEN :
{
  < RUNSIGNEDSHIFT: ">>>" >
  {
     matchedToken.kind = GT;
     ((Token.GTToken)matchedToken).realKind = RUNSIGNEDSHIFT;
     input_stream.backup(2);
  }
| < RSIGNEDSHIFT: ">>" >
  {
     matchedToken.kind = GT;
     ((Token.GTToken)matchedToken).realKind = RSIGNEDSHIFT;
     input_stream.backup(1);
  }
| < GT: ">" >
}


/*****************************************
 * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
 *****************************************/

/*
 * Program structuring syntax follows.
 */

void CompilationUnit():
{}
{
  [ PackageDeclaration() ]
  ( ImportDeclaration() )*
  ( TypeDeclaration() )*
  <EOF>
}

void PackageDeclaration():
{}
{
  "package" { parser2.add(J_PACKAGE, token); }
  Name() ";"
    
}

void ImportDeclaration():
{}
{
  "import" { parser2.add(J_IMPORT, token); }
  [ "static" ] Name() [ "." "*" ] ";"
}

/*
 * Modifiers. We match all modifiers in a single rule to reduce the chances of
 * syntax errors for simple modifier mistakes. It will also enable us to give
 * better error messages.
 */

int Modifiers():
{
   int modifiers = 0;
}
{
 (
  LOOKAHEAD(2)
  (
   "public" { modifiers |= ModifierSet.PUBLIC; }
  |
   "static" { modifiers |= ModifierSet.STATIC; }
  |
   "protected" { modifiers |= ModifierSet.PROTECTED; }
  |
   "private" { modifiers |= ModifierSet.PRIVATE; }
  |
   "final" { modifiers |= ModifierSet.FINAL; }
  |
   "abstract" { modifiers |= ModifierSet.ABSTRACT; }
  |
   "synchronized" { modifiers |= ModifierSet.SYNCHRONIZED; }
  |
   "native" { modifiers |= ModifierSet.NATIVE; }
  |
   "transient" { modifiers |= ModifierSet.TRANSIENT; }
  |
   "volatile" { modifiers |= ModifierSet.VOLATILE; }
  |
   "strictfp" { modifiers |= ModifierSet.STRICTFP; }
  |
   Annotation()
  )
 )*

 {
    return modifiers;
 }
}

/*
 * Declaration syntax follows.
 */
void TypeDeclaration():
{
   int modifiers;
}
{
  ";"
|
  modifiers = Modifiers()
  (
     ClassOrInterfaceDeclaration(modifiers)
   |
     EnumDeclaration(modifiers)
   |
     AnnotationTypeDeclaration(modifiers)
  )
}


void ClassOrInterfaceDeclaration(int modifiers):
{
   boolean isInterface = false;
}
{
  ( "class" | "interface" { isInterface = true; } )
        { parser2.add((isInterface ? J_INTERFACE_BEGIN : J_CLASS_BEGIN), token); }
  <IDENTIFIER>
  [ TypeParameters() ]
  [ ExtendsList(isInterface) ]
  [ ImplementsList(isInterface) ]
  ClassOrInterfaceBody(isInterface)
      { parser2.add((isInterface ? J_INTERFACE_END : J_CLASS_END), token); }
}

void ExtendsList(boolean isInterface):
{
   boolean extendsMoreThanOne = false;
}
{
   "extends" ClassOrInterfaceType()
   ( "," ClassOrInterfaceType() { extendsMoreThanOne = true; } )*
   {
      if (extendsMoreThanOne && !isInterface)
         throw new ParseException("A class cannot extend more than one other class");
   }
}

void ImplementsList(boolean isInterface):
{}
{
   "implements" ClassOrInterfaceType()
   ( "," ClassOrInterfaceType() )*
   {
      if (isInterface)
         throw new ParseException("An interface cannot implement other interfaces");
   }
}

void EnumDeclaration(int modifiers):
{}
{
  "enum"							  { parser2.add(J_ENUM_BEGIN, token); }
  <IDENTIFIER>
  [ ImplementsList(false) ]
  EnumBody()                          { parser2.add(J_ENUM_END, token); }
}

void EnumBody():
{}
{
   "{"
   EnumConstant() ( "," EnumConstant() )*
   [ ";"                             { parser2.add(J_ENUM_CLASS_BEGIN, token); }
     ( ClassOrInterfaceBodyDeclaration(false) )* ]
   "}"
}

void EnumConstant():
{}
{
  <IDENTIFIER> [ Arguments() ] [ ClassOrInterfaceBody(false) ]
}

void TypeParameters():
{}
{
   "<" TypeParameter() ( "," TypeParameter() )* ">"
}

void TypeParameter():
{}
{
   <IDENTIFIER> [ TypeBound() ]
}

void TypeBound():
{}
{
   "extends" ClassOrInterfaceType() ( "&" ClassOrInterfaceType() )*
}

void ClassOrInterfaceBody(boolean isInterface):
{}
{
  "{" ( ClassOrInterfaceBodyDeclaration(isInterface) )* "}"
}

void ClassOrInterfaceBodyDeclaration(boolean isInterface):
{
   boolean isNestedInterface = false;
   int modifiers;
}
{
  LOOKAHEAD(2)
  Initializer()
  {
     if (isInterface)
        throw new ParseException("An interface cannot have initializers");
  }
|
  modifiers = Modifiers() // Just get all the modifiers out of the way. If you want to do
              // more checks, pass the modifiers down to the member
  (
      ClassOrInterfaceDeclaration(modifiers)
    |
      EnumDeclaration(modifiers)
    |
      LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" )
      ConstructorDeclaration()
    |
      LOOKAHEAD( Type() <IDENTIFIER> ( "[" "]" )* ( "," | "=" | ";" ) )
      FieldDeclaration(modifiers)
    |
      MethodDeclaration(modifiers)
  )
|
  ";"
}

void FieldDeclaration(int modifiers):
{}
{
  // Modifiers are already matched in the caller
  Type() VariableDeclarator() ( "," VariableDeclarator() )* ";"
}

void VariableDeclarator():
{}
{
  <IDENTIFIER>                  		  { parser2.add(J_VARDEF, token); }
  ( "[" "]" )*
  [ "="                                   { parser2.add(J_ASSIGN, token); }
  VariableInitializer() ]
}

void VariableDeclaratorId():
{}
{
  <IDENTIFIER> ( "[" "]" )*
}

void VariableInitializer():
{}
{
  ArrayInitializer()
|
  Expression()
}

void ArrayInitializer():
{}
{
  "{"								{ parser2.add(J_ARRAY_INIT_BEGIN, token); }
  [ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ]
  "}"								{ parser2.add(J_ARRAY_INIT_END, token); }
}

void MethodDeclaration(int modifiers):
{}
{
  // Modifiers already matched in the caller!
  [ TypeParameters() ]
  ResultType()
  MethodDeclarator() [ "throws" NameList() ]
      ( Block() | ";" )                 { parser2.add(J_METHOD_END, token); parser2.add(SEPARATOR_TOKEN, token); }
}

void MethodDeclarator():
{}
{
  <IDENTIFIER>                          { parser2.add(SEPARATOR_TOKEN, token); parser2.add(J_METHOD_BEGIN, token); }
  FormalParameters() ( "[" "]" )*
}

void FormalParameters():
{}
{
  "(" [ FormalParameter() ( "," FormalParameter() )* ] ")"
}

void FormalParameter():
{}
{
  ("final" | Annotation())* Type() [ "..." ] VariableDeclaratorId()
}

void ConstructorDeclaration():
{}
{
  [ TypeParameters() ]
  // Modifiers matched in the caller
  <IDENTIFIER>                         { parser2.add(SEPARATOR_TOKEN, token); parser2.add(J_CONSTR_BEGIN, token); }
  FormalParameters() [ "throws" NameList() ]
  "{"
    [ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ]
    ( BlockStatement() )*
  "}"                                  { parser2.add(J_CONSTR_END, token); parser2.add(SEPARATOR_TOKEN, token); }
}

void ExplicitConstructorInvocation():
{}
{
  LOOKAHEAD("this" Arguments() ";")
  "this"                               { parser2.add(J_APPLY, token); }
  Arguments() ";"
|
  [ LOOKAHEAD(2) PrimaryExpression() "." ]
  "super"                              { parser2.add(J_APPLY, token); }
  Arguments() ";"
}

void Initializer():
{}
{
  InitializerBegin()
  ( BlockStatement() )* "}"            { parser2.add(J_INIT_END, token); }
}

void InitializerBegin():
{}
{
  "static"							   { parser2.add(J_INIT_BEGIN, token); }
  "{"
|
  "{"								   { parser2.add(J_INIT_BEGIN, token); }
}

/*
 * Type, name and expression syntax follows.
 */

void Type():
{}
{
   LOOKAHEAD(2) ReferenceType()
 |
   PrimitiveType()
}

void ReferenceType():
{}
{
   PrimitiveType() ( LOOKAHEAD(2) "[" "]" )+
  |
   ( ClassOrInterfaceType() ) ( LOOKAHEAD(2) "[" "]" )*
}

void ClassOrInterfaceType():
{}
{
  <IDENTIFIER> [ LOOKAHEAD(2) TypeArguments() ]
  ( LOOKAHEAD(2) "." <IDENTIFIER> [ LOOKAHEAD(2) TypeArguments() ] )*
}

void TypeArguments():
{}
{
   "<" TypeArgument()                  { parser2.add(J_GENERIC, token); }
   ( "," TypeArgument()                { parser2.add(J_GENERIC, token); }
   )* ">"
}

void TypeArgument():
{}
{
   ReferenceType()
 |
   "?" [ WildcardBounds() ]
}

void WildcardBounds():
{}
{
   "extends" ReferenceType()
 |
   "super" ReferenceType()
}


void PrimitiveType():
{}
{
  "boolean"
|
  "char"
|
  "byte"
|
  "short"
|
  "int"
|
  "long"
|
  "float"
|
  "double"
}

void ResultType():
{}
{
  "void"                               { parser2.add(J_VOID, token); }
|
  Type()
}

void Name():
/*
 * A lookahead of 2 is required below since "Name" can be followed
 * by a ".*" when used in the context of an "ImportDeclaration".
 */
{}
{
  <IDENTIFIER>
  ( LOOKAHEAD(2) "." <IDENTIFIER>
  )*
}

void NameList():
{}
{
  Name() ( "," Name() )*
}


/*
 * Expression syntax follows.
 */

void Expression():
/*
 * This expansion has been written this way instead of:
 *   Assignment() | ConditionalExpression()
 * for performance reasons.
 * However, it is a weakening of the grammar for it allows the LHS of
 * assignments to be any conditional expression whereas it can only be
 * a primary expression.  Consider adding a semantic predicate to work
 * around this.
 */
{}
{
  ConditionalExpression()
  [
    LOOKAHEAD(2)
    AssignmentOperator() Expression()
  ]
}

void AssignmentOperator():
{}
{
    ("=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=")                                  { parser2.add(J_ASSIGN, token); }
}

void ConditionalExpression():
{}
{
  ConditionalOrExpression()
  [ "?"                                     { parser2.add(J_COND, token); }
    Expression() ":" Expression() ]
}

void ConditionalOrExpression():
{}
{
  ConditionalAndExpression() ( "||" ConditionalAndExpression() )*
}

void ConditionalAndExpression():
{}
{
  InclusiveOrExpression() ( "&&" InclusiveOrExpression() )*
}

void InclusiveOrExpression():
{}
{
  ExclusiveOrExpression() ( "|" ExclusiveOrExpression() )*
}

void ExclusiveOrExpression():
{}
{
  AndExpression() ( "^" AndExpression() )*
}

void AndExpression():
{}
{
  EqualityExpression() ( "&" EqualityExpression() )*
}

void EqualityExpression():
{}
{
  InstanceOfExpression() ( ( "==" | "!=" ) InstanceOfExpression() )*
}

void InstanceOfExpression():
{}
{
  RelationalExpression() [ "instanceof" Type() ]
}

void RelationalExpression():
{}
{
  ShiftExpression() ( ( "<" | ">" | "<=" | ">=" ) ShiftExpression() )*
}

void ShiftExpression():
{}
{
  AdditiveExpression() ( ( "<<" | RSIGNEDSHIFT() | RUNSIGNEDSHIFT() ) AdditiveExpression() )*
}

void AdditiveExpression():
{}
{
  MultiplicativeExpression() ( ( "+" | "-" ) MultiplicativeExpression() )*
}

void MultiplicativeExpression():
{}
{
  UnaryExpression() ( ( "*" | "/" | "%" ) UnaryExpression() )*
}

void UnaryExpression():
{}
{
  ( "+" | "-" ) UnaryExpression()
|
  PreIncrementExpression()
|
  PreDecrementExpression()
|
  UnaryExpressionNotPlusMinus()
}

void PreIncrementExpression():
{}
{
  "++"                                    { parser2.add(J_ASSIGN, token); }
  PrimaryExpression()
}

void PreDecrementExpression():
{}
{
  "--"                                    { parser2.add(J_ASSIGN, token); }
  PrimaryExpression()
}

void UnaryExpressionNotPlusMinus():
{}
{
  ( "~" | "!" ) UnaryExpression()
|
  LOOKAHEAD( CastLookahead() )
  CastExpression()
|
  PostfixExpression()
}

// This production is to determine lookahead only.  The LOOKAHEAD specifications
// below are not used, but they are there just to indicate that we know about
// this.
void CastLookahead():
{}
{
  LOOKAHEAD(2)
  "(" PrimitiveType()
|
  LOOKAHEAD("(" Type() "[")
  "(" Type() "[" "]"
|
  "(" Type() ")" ( "~" | "!" | "(" | <IDENTIFIER> | "this" | "super" | "new" | Literal() )
}

void PostfixExpression():
{}
{
  PrimaryExpression()
  [ ( "++" | "--" )                       { parser2.add(J_ASSIGN, token); }
  ]
}

void CastExpression():
{}
{
  LOOKAHEAD("(" PrimitiveType())
  "(" Type() ")" UnaryExpression()
|
  "(" Type() ")" UnaryExpressionNotPlusMinus()
}

void PrimaryExpression():
{}
{
  PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )*
}

void MemberSelector():
{}
{
  "." TypeArguments() <IDENTIFIER>
}

void PrimaryPrefix():
{}
{
  Literal()
|
  "this"
|
  "super" "." <IDENTIFIER>
|
  "(" Expression() ")"
|
  AllocationExpression()
|
  LOOKAHEAD( ResultType() "." "class" )
  ResultType() "." "class"
|
  Name()
}

void PrimarySuffix():
{}
{
(
  LOOKAHEAD(2)
  "." "this"
|
  LOOKAHEAD(2)
  "." "super" "." <IDENTIFIER>
|
  LOOKAHEAD(2)
  "." AllocationExpression()
|
  LOOKAHEAD(3)
  MemberSelector()
|
  "[" Expression() "]"
|
  "." <IDENTIFIER>
|
  	{ parser2.add(J_APPLY, token); }
  Arguments()
)
}

void Literal():
{}
{
  <INTEGER_LITERAL>
|
  <FLOATING_POINT_LITERAL>
|
  <CHARACTER_LITERAL>
|
  <STRING_LITERAL>
|
  BooleanLiteral()
|
  NullLiteral()
}

void BooleanLiteral():
{}
{
  "true"
|
  "false"
}

void NullLiteral():
{}
{
  "null"
}

void Arguments():
{}
{
  "(" [ ArgumentList() ] ")"
}

void ArgumentList():
{}
{
  Expression() ( "," Expression() )*
}

void AllocationExpression():
{
  Token x;
}
{
  LOOKAHEAD(2)
  "new"                                     { parser2.add(J_NEWARRAY, token); }
  PrimitiveType() ArrayDimsAndInits()
|
  x="new"
  ClassOrInterfaceType() [ TypeArguments() ]
    (                                       { parser2.add(J_NEWARRAY, x); }
      ArrayDimsAndInits()
    |										{ parser2.add(J_NEWCLASS, x); }
      Arguments()
      [
        "{"                           { parser2.add(J_IN_CLASS_BEGIN, token); }
        ( ClassOrInterfaceBodyDeclaration(false) )* "}"
        							  { parser2.add(J_IN_CLASS_END, token); }
      ]
    )
}

/*
 * The third LOOKAHEAD specification below is to parse to PrimarySuffix
 * if there is an expression between the "[...]".
 */
void ArrayDimsAndInits():
{}
{
  LOOKAHEAD(2)
  ( LOOKAHEAD(2) "[" Expression() "]" )+ ( LOOKAHEAD(2) "[" "]" )*
|
  ( "[" "]" )+ ArrayInitializer()
}


/*
 * Statement syntax follows.
 */

void Statement():
{}
{
  LOOKAHEAD(2)
  LabeledStatement()
|
  AssertStatement()
|
  Block()
|
  EmptyStatement()
|
  StatementExpression() ";"
|
  SwitchStatement()
|
  IfStatement()
|
  WhileStatement()
|
  DoStatement()
|
  ForStatement()
|
  BreakStatement()
|
  ContinueStatement()
|
  ReturnStatement()
|
  ThrowStatement()
|
  SynchronizedStatement()
|
  TryStatement()
}

void AssertStatement():
{}
{
  "assert"                                  { parser2.add(J_ASSERT, token); }
  Expression() [ ":" Expression() ] ";"
}

void LabeledStatement():
{}
{
  <IDENTIFIER> ":" Statement()
}

void Block():
{}
{
  "{" ( BlockStatement() )* "}"
}

void BlockStatement():
{}
{
  LOOKAHEAD(("final" | Annotation())* Type() <IDENTIFIER>)
  LocalVariableDeclaration() ";"
|
  Statement()
|
  ClassOrInterfaceDeclaration(0)
}

void LocalVariableDeclaration():
{}
{
  ("final" | Annotation())* Type() VariableDeclarator() ( "," VariableDeclarator() )*
}

void EmptyStatement():
{}
{
  ";"
}

void StatementExpression():
/*
 * The last expansion of this production accepts more than the legal
 * Java expansions for StatementExpression.  This expansion does not
 * use PostfixExpression for performance reasons.
 */
{}
{
  PreIncrementExpression()
|
  PreDecrementExpression()
|
  PrimaryExpression()
  [
    "++"                               { parser2.add(J_ASSIGN, token); }
  |
    "--"                               { parser2.add(J_ASSIGN, token); }
  |
    AssignmentOperator() Expression()
  ]
}

void SwitchStatement():
{}
{
  "switch"                             { parser2.add(J_SWITCH_BEGIN, token); }
  "(" Expression() ")" "{"
    ( SwitchLabel()
      ( BlockStatement() )*
    )*
  "}"                                  { parser2.add(J_SWITCH_END, token); }
}

void SwitchLabel():
{}
{
  "case"							   { parser2.add(J_CASE, token); }
  Expression() ":"
|
  "default"							   { parser2.add(J_CASE, token); }
  ":"
}

void IfStatement():
/*
 * The disambiguating algorithm of JavaCC automatically binds dangling
 * else's to the innermost if statement.  The LOOKAHEAD specification
 * is to tell JavaCC that we know what we are doing.
 */
{}
{
  "if"                                 { parser2.add(J_IF_BEGIN, token); }
  "(" Expression() ")" Statement()
  [ LOOKAHEAD(1) "else"                { parser2.add(J_ELSE, token); }
    Statement() ]
                                       { parser2.add(J_IF_END, token); }
}

void WhileStatement():
{}
{
  "while"                              { parser2.add(J_WHILE_BEGIN, token); }
  "(" Expression() ")" Statement()     { parser2.add(J_WHILE_END, token); }
}

void DoStatement():
{}
{
  "do"                                 { parser2.add(J_DO_BEGIN, token); }
  Statement() "while" "(" Expression() ")" ";"
                                       { parser2.add(J_DO_END, token); }
}

void ForStatement():
{}
{
  "for"                                { parser2.add(J_FOR_BEGIN, token); }
  "("
  (
      LOOKAHEAD(("final" | Annotation())* Type() <IDENTIFIER> ":")
      ("final" | Annotation())* Type() <IDENTIFIER>
      ":" Expression() 
    |
     [ ForInit() ] ";" [ Expression() ] ";" [ ForUpdate() ]
  )

  ")" Statement()
                                       { parser2.add(J_FOR_END, token); }
}

void ForInit():
{}
{
  LOOKAHEAD( [ "final" ] Type() <IDENTIFIER> )
  LocalVariableDeclaration()
|
  StatementExpressionList()
}

void StatementExpressionList():
{}
{
  StatementExpression() ( "," StatementExpression() )*
}

void ForUpdate():
{}
{
  StatementExpressionList()
}

void BreakStatement():
{}
{
  "break"                              { parser2.add(J_BREAK, token); }
  [ <IDENTIFIER> ] ";"
}

void ContinueStatement():
{}
{
  "continue"                           { parser2.add(J_CONTINUE, token); }
  [ <IDENTIFIER> ] ";"
}

void ReturnStatement():
{}
{
  "return"							   { parser2.add(J_RETURN, token); }
  [ Expression() ] ";"
}

void ThrowStatement():
{}
{
  "throw"                              { parser2.add(J_THROW, token); }
  Expression() ";"
}

void SynchronizedStatement():
{}
{
  "synchronized"                       { parser2.add(J_SYNC_BEGIN, token); }
  "(" Expression() ")" Block()         { parser2.add(J_SYNC_END, token); }
}

void TryStatement():
/*
 * Semantic check required here to make sure that at least one
 * finally/catch is present.
 */
{}
{
  "try"                                { parser2.add(J_TRY_BEGIN, token); }
  Block()
  ( "catch"                            { parser2.add(J_CATCH_BEGIN, token); }
    "(" FormalParameter() ")" Block() )*
  [ "finally"                          { parser2.add(J_FINALLY, token); }
    Block() ]                          { parser2.add(J_CATCH_END, token); }
}

/* We use productions to match >>>, >> and > so that we can keep the
 * type declaration syntax with generics clean
 */

void RUNSIGNEDSHIFT():
{}
{
  ( LOOKAHEAD({ getToken(1).kind == GT &&
                ((Token.GTToken)getToken(1)).realKind == RUNSIGNEDSHIFT} )
   ">" ">" ">"
  )
}

void RSIGNEDSHIFT():
{}
{
  ( LOOKAHEAD({ getToken(1).kind == GT &&
                ((Token.GTToken)getToken(1)).realKind == RSIGNEDSHIFT} )
  ">" ">"
  )
}

/* Annotation syntax follows. */

void Annotation():
{}
{
   LOOKAHEAD( "@" Name() "(" ( <IDENTIFIER> "=" | ")" ))
   NormalAnnotation()
 |
   LOOKAHEAD( "@" Name() "(" )
   SingleMemberAnnotation()
 |
   MarkerAnnotation()
}

void NormalAnnotation():
{}
{
   "@"                                  { parser2.add(J_ANNO, token); }
   Name()
   "(" [ MemberValuePairs() ] ")"
}

void MarkerAnnotation():
{}
{
  "@"                                   { parser2.add(J_ANNO_MARKER, token); }
  Name()
}

void SingleMemberAnnotation():
{}
{
  "@"                                   { parser2.add(J_ANNO, token); }
  Name() "(" MemberValue() ")"
}

void MemberValuePairs():
{}
{
   MemberValuePair() ( "," MemberValuePair() )*
}

void MemberValuePair():
{}
{
    <IDENTIFIER> "=" MemberValue()
}

void MemberValue():
{}
{
   Annotation()
 |
   MemberValueArrayInitializer()
 |
   ConditionalExpression()
}

void  MemberValueArrayInitializer():
{}
{
  "{"                                   { parser2.add(J_ANNO_M_BEGIN, token); }
  MemberValue() ( LOOKAHEAD(2) "," MemberValue() )* [ "," ]
  "}"                                   { parser2.add(J_ANNO_M_END, token); }
}


/* Annotation Types. */

void AnnotationTypeDeclaration(int modifiers):
{}
{
  "@"                                   { parser2.add(J_ANNO_T_BEGIN, token); }
  "interface" <IDENTIFIER> AnnotationTypeBody()
                                        { parser2.add(J_ANNO_T_END, token); }
}

void AnnotationTypeBody():
{}
{
  "{" ( AnnotationTypeMemberDeclaration() )* "}"
}

void AnnotationTypeMemberDeclaration():
{
   int modifiers;
}
{
 modifiers = Modifiers()
 (
   LOOKAHEAD(Type() <IDENTIFIER> "(")
   Type() <IDENTIFIER>
   "(" ")" [ DefaultValue() ] ";"
  |
                                        { parser2.add(J_ANNO_C_BEGIN, token); }
   ClassOrInterfaceDeclaration(modifiers)
                                        { parser2.add(J_ANNO_C_END, token); }
  |
   EnumDeclaration(modifiers)
  |
   AnnotationTypeDeclaration(modifiers)
  |
   FieldDeclaration(modifiers)
 )
 |
   ( ";" )
}

void DefaultValue():
{}
{
  "default" MemberValue()
}
